import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.*;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author Melinton
 */
class Automata 
{
    //--------------------------------------------------------------------------
    // CONSTANTES
    //--------------------------------------------------------------------------
    public static final int AFD = 0;
    public static final int AFN = 1;
    
    
    //--------------------------------------------------------------------------
    // ATRIBUTOS
    //--------------------------------------------------------------------------
    public int tipo;
    public ArrayList<Estado> estados;
    public Estado estadoInicial;
    public ArrayList<Estado> estadosFinales;
    public ArrayList<Funcion> funciones;  
    public ArrayList<String> lenguaje;
    public Stack<Funcion> seguimientoSimulacion;
    
    //--------------------------------------------------------------------------
    // CONSTRUCTOR  
    //--------------------------------------------------------------------------
    public Automata(Estado eInicial)
    {
        tipo = AFN;
        estados = new ArrayList();
        estadoInicial = eInicial;
        estadosFinales = new ArrayList();
        funciones = new ArrayList();
        lenguaje = new ArrayList();
        seguimientoSimulacion = new Stack();
    }
    
    public Automata(Estado initialEst, ArrayList<Estado> est, ArrayList<Estado> finales, ArrayList<Funcion> func, ArrayList<String> leng, int type)
    {
        estados = est;
        estadosFinales = finales;
        funciones = func;
        lenguaje = leng;
        estadoInicial = initialEst;
        tipo = type;
    }        
    
    //--------------------------------------------------------------------------
    // MÉTODOS  
    //--------------------------------------------------------------------------        
    public ArrayList<Estado> mover(ArrayList<Estado> q, String simbolo )
    {
        //Funcion de mover para AFN
        ArrayList<Estado> u = new ArrayList();
        for(int i = 0; i < q.size(); i++)
        {
            for(int w = 0; w < funciones.size(); w++)
            {
                if(funciones.get(w).estado.equals(q.get(i)) && funciones.get(w).simbolo.equals(simbolo))
                {
                    u.add(funciones.get(w).estadoResultante);
                    seguimientoSimulacion.push(funciones.get(w));
                }
            }
        }
        return u;
    }
    
    public ArrayList<Estado> cerraduraEpsilon(ArrayList<Estado> T)
    {
        ArrayList<Estado> cerraduraE = new ArrayList();
        Stack<Estado> pila = new Stack();
        Estado t;
        for(int i = 0; i < T.size(); i++)
        {
            pila.push(T.get(i));
            cerraduraE.add(T.get(i));
        }
        while(!pila.isEmpty())
        {
            t = pila.pop();            
            for(int u = 0; u < funciones.size(); u++)
            {
                if(funciones.get(u).estado.equals(t) && funciones.get(u).simbolo.equals("¬"))
                {                    
                    if(!(cerraduraE.contains((Estado) funciones.get(u).estadoResultante)))
                    {
                        cerraduraE.add(funciones.get(u).estadoResultante);
                        pila.push(funciones.get(u).estadoResultante);
                    }
                }
            }
        }
        return cerraduraE;
    }
    
    public Automata toAFD() 
    {
        ArrayList<Funcion> funcs = new ArrayList();
        Estado inicial = new Estado(Integer.toString(0));
        ArrayList<Estado> estads = new ArrayList();
        ArrayList<Estado> finales = new ArrayList();
        ArrayList<Estado> q_0f = new ArrayList();
        q_0f.add(estadoInicial);
        ArrayList<Estado> q_0d = cerraduraEpsilon(q_0f);
        HashMap Q_D = new HashMap();
        Q_D.put(inicial, q_0d);
        for(int i = 0; i < Q_D.size(); i++)
        {
            ArrayList<Estado> q = new ArrayList();
            Iterator states = Q_D.keySet().iterator();            
            Estado actual = null;
            Estado fin = null;
            while(states.hasNext())
            {
                Estado piv = (Estado) states.next();                
                if(piv.valor.equals(Integer.toString(i)))
                {
                    q = (ArrayList<Estado>) Q_D.get(piv);
                    actual = piv;
                }
            }
            for(int u=0; u < lenguaje.size(); u++)
            {
                ArrayList<Estado> U_F = cerraduraEpsilon(mover(q,lenguaje.get(u)));
                states = Q_D.keySet().iterator();
                boolean existe = false; 
                while(states.hasNext() && !existe)
                {
                    Estado piv = (Estado) states.next();                    
                    if(compararArrays(U_F,(ArrayList) Q_D.get(piv)))
                    {
                        existe = true;
                        fin = piv;
                    }
                }
                if(existe)
                {
                    Funcion func = new Funcion(actual, lenguaje.get(u), fin);
                    funcs.add(func);
                }
                else if(!U_F.isEmpty())
                {
                    Estado est = new Estado(Integer.toString(Q_D.size()));
                    Funcion func = new Funcion(actual, lenguaje.get(u), est);
                    funcs.add(func);
                    Q_D.put(est, U_F);
                }
            }
            boolean prueba = false;
            for(int h = 0; h < funcs.size() && !prueba; h++)
            {                
                if(funcs.get(h).estado.equals(actual) && funcs.get(h).simbolo.equals("¬"))
                    prueba = true;
            }
            if(!prueba)
                funcs.add(new Funcion(actual, "¬", actual));
        }        
            Estado ultimo = estadosFinales.get(0);
            Iterator estates = Q_D.keySet().iterator();
            while(estates.hasNext())
            {
                Estado piv = (Estado) estates.next();
                estads.add(piv);
                ArrayList<Estado> estds = (ArrayList<Estado>) Q_D.get(piv); 
                if (estds.contains(ultimo))
                    finales.add(piv);
            }              
        Automata AFD = new Automata(inicial, estads, finales, funcs, lenguaje, Automata.AFD);
        AFD.lenguaje = lenguaje;
        return AFD;
    }
    
     public void anhadirFuncion(Funcion func)
    {
        funciones.add(func);
    }
    
    public void anhadirEstadoFinal(Estado fin)
    {
        estadosFinales.add(fin);
    }
    
    public void anhadirAlLenguaje(ArrayList<String> leng)
    {
        for(int i = 0; i < leng.size(); i++)
        {
            if(!lenguaje.contains(leng.get(i)))
                lenguaje.add(leng.get(i));
        }
        
    }
       
    public boolean compararArrays(ArrayList a, ArrayList b)
    {
        if(a.containsAll(b) && a.size()==b.size())
            return true;
        else
            return false; 
    }
}

/**
 *
 * @author Melinton
 */
class Estado 
{
    //--------------------------------------------------------------------------
    // ATRIBUTOS
    //--------------------------------------------------------------------------
    public String valor;
    public ArrayList<String> simbolosPosibles;
    public ArrayList<Estado> estadosPosibles;
    
    //--------------------------------------------------------------------------
    // MÉTODOS  
    //--------------------------------------------------------------------------
    public Estado(String val)
    {
        valor = val;
        simbolosPosibles = new ArrayList();
        estadosPosibles = new ArrayList();
    }
}

class Funcion 
{
    //--------------------------------------------------------------------------
    // ATRIBUTOS
    //--------------------------------------------------------------------------
    public Estado estado;
    public String simbolo;
    public Estado estadoResultante;
    
    //--------------------------------------------------------------------------
    // CONSTRUCTOR
    //--------------------------------------------------------------------------
    public Funcion(Estado est, String sim, Estado estResult)
    {
        estado = est;
        simbolo = sim;
        estadoResultante = estResult;
    }
    
}

class Node 
{
    //--------------------------------------------------------------------------
    // ATRIBUTOS
    //--------------------------------------------------------------------------
    private Node hijoDerecho;
    private Node hijoIzquierdo;
    private Node padre;
    private String contenido;
    
    //--------------------------------------------------------------------------
    // CONSTRUCTOR
    //--------------------------------------------------------------------------
    public Node(String cont)
    {
        hijoDerecho = null;        
        hijoIzquierdo = null;
        padre = null;
        contenido = cont;
    }
    
    //--------------------------------------------------------------------------
    // MÉTODOS
    //--------------------------------------------------------------------------
    public Node darHijoDerecho()
    {
        return hijoDerecho;
    }
    
    public Node darHijoIzquierdo()
    {
        return hijoIzquierdo;
    }
    
    public Node darPadre()
    {
        return padre;
    }
    
    public String darContenido()
    {
        return contenido;
    }
    
    public void setHijoIzquierdo(Node izquierdo)
    {
        hijoIzquierdo = izquierdo;
    }
    
    public void setHijoDerecho(Node derecho)
    {
        hijoDerecho = derecho; 
    }
    
    public void setPadre(Node nodoPadre)
    {
        padre = nodoPadre; 
    }
}

class Operador 
{
    private String valor;
    private int prioridad;
    
    public Operador(String v, int prior)
    {
        valor = v;
        prioridad = prior;
    }
    
    public String darValor()
    {
        return valor;
    }
    
    public int darPrioridad()
    {
        return prioridad;
    }
}

class Parser 
{
    //--------------------------------------------------------------------------
    // ATRIBUTOS
    //--------------------------------------------------------------------------
    ArrayList<String> regex;
    Stack<Operador> tokens;    
    HashMap pp;
    HashMap sp;
    int contadorEstados;    
    
    //--------------------------------------------------------------------------
    // CONSRTUCTOR
    //--------------------------------------------------------------------------
    public Parser()
    {
        regex = new ArrayList();
        tokens = new Stack();
        pp = new HashMap();
        sp = new HashMap();
        contadorEstados = 0;        
    }
    
    //--------------------------------------------------------------------------
    // MÉTODOS
    //--------------------------------------------------------------------------
    public ArrayList<String> convertirAPosfix(String cadena) 
    {
        
        try {
            if(validarCadena(cadena))
                parsearCadena(cadena);
        } catch (Exception ex) {
            Logger.getLogger(Parser.class.getName()).log(Level.SEVERE, null, ex);            
        }             
        
        return regex;
    }
    
    public void parsearCadena(String cadena) throws Exception
    {   
        //validarCadena(cadena);
        for(int i=0; i<cadena.length(); i++)
        {
            int a = (i>0)?(i-1):i;
            if(cadena.charAt(i) == '(')
            {                
                if(a>=0&&a!=i)
                {
                    while(!tokens.isEmpty() && (tokens.peek().darPrioridad()>=0))
                    {
                        regex.add(tokens.pop().darValor());                        
                    }
                    if(i>0)
                    {
                        if(cadena.charAt(i-1)!='|' || cadena.charAt(i-1)!='(')//if(cadena.charAt(i-1)==')' || cadena.charAt(i-1)=='*' || Character.isLetterOrDigit(cadena.charAt(i-1)) || cadena.charAt(i-1)=='#')
                            tokens.push(new Operador(".",0));
                    }
                }
                tokens.push(new Operador("" + cadena.charAt(i), -1));
            }

            else if(cadena.charAt(i)==')')
            {
                while(!tokens.isEmpty() && !tokens.peek().darValor().equals("("))
                {
                    regex.add(tokens.pop().darValor());
                }
                tokens.pop();
            }
            else if(cadena.charAt(i)=='*' || cadena.charAt(i)=='|')
            {
                Operador pivote;
                if(cadena.charAt(i)=='*')
                    pivote = new Operador("" + cadena.charAt(i), 2);
                else
                    pivote = new Operador("" + cadena.charAt(i), 1);
                if(tokens.isEmpty())
                    tokens.push(pivote);
                else
                {
                    while(!tokens.isEmpty() && tokens.peek().darPrioridad()>=pivote.darPrioridad())
                    {
                        regex.add(tokens.pop().darValor());                        
                    }
                    tokens.push(pivote);                    
                }
            }
            else if(Character.isLetterOrDigit(cadena.charAt(i)) || cadena.charAt(i)=='#' || cadena.charAt(i)=='¬')
            {
                if(cadena.charAt(a)!='|' && cadena.charAt(a)!='(' && a>=0 && a!=i)
                {
                    while(!tokens.isEmpty() && (tokens.peek().darPrioridad()>=0))
                    {
                        regex.add(tokens.pop().darValor());                        
                    }
                    tokens.push(new Operador(".",0));
                }
                regex.add("" + cadena.charAt(i));
            }            
        }           
        while(!tokens.isEmpty())
        {
            regex.add(tokens.pop().darValor());
        }
    }
    
    public Node crearArbol()
    {
        Stack<Node> pila = new Stack();
        for(int u=0; u<regex.size(); u++)
        {
            switch(regex.get(u))
            {
                case "*":
                    Node nodo0 = new Node("*");
                    Node nodoHijo0 = pila.pop();
                    nodo0.setHijoIzquierdo(nodoHijo0);
                    nodoHijo0.setPadre(nodo0);
                    pila.push(nodo0);
                    break;                                    
                case "|":
                    Node nodo3 = new Node("|");                    
                    Node nodoHijoIzq;                    
                    Node nodoHijoDer;
                    if(pila.peek().darContenido().equals("."))
                    {
                        nodoHijoIzq = pila.pop();
                        nodoHijoDer = pila.pop();
                    }
                    else                        
                    {
                        nodoHijoDer = pila.pop();
                        nodoHijoIzq = pila.pop();
                    }
                    nodo3.setHijoDerecho(nodoHijoDer);
                    nodo3.setHijoIzquierdo(nodoHijoIzq);
                    nodoHijoIzq.setPadre(nodo3);
                    nodoHijoDer.setPadre(nodo3);
                    pila.push(nodo3);
                    break;
                case ".":
                    Node nodo4 = new Node("."); 
                    Node nodoHijoIzq1;
                    Node nodoHijoDer1;
                    if(pila.peek().darContenido().equals("."))
                    {
                        nodoHijoIzq1 = pila.pop();
                        nodoHijoDer1 = pila.pop();
                    }
                    else                        
                    {
                        nodoHijoDer1 = pila.pop();
                        nodoHijoIzq1 = pila.pop();
                    }                    
                        
                    nodo4.setHijoDerecho(nodoHijoDer1);
                    nodo4.setHijoIzquierdo(nodoHijoIzq1);
                    nodoHijoIzq1.setPadre(nodo4);
                    nodoHijoDer1.setPadre(nodo4);
                    pila.push(nodo4);
                    break;
                default:
                    Node nodo5 = new Node(regex.get(u));
                    pila.push(nodo5);
                    break;
                    
            }
        }
        return pila.pop();
    }
    
    public Automata thompson(Node raiz, ArrayList<String> leng, Estado izquierdaFinal) 
    {        
        switch(raiz.darContenido())
        {            
            case "¬":
                ArrayList<Estado> estadosEp = new ArrayList();                
                ArrayList<Estado> estadosFinales = new ArrayList();
                ArrayList<Funcion> funcionesEp = new ArrayList(); 
                Estado estadoQ_0;
                if(izquierdaFinal!=null)
                    estadoQ_0 = izquierdaFinal;
                else
                    estadoQ_0 = new Estado("S"+contadorEstados);                                
                estadosEp.add(estadoQ_0);
                if(estadoQ_0 != izquierdaFinal)
                    contadorEstados++;                
                Estado estado2 = new Estado("S"+Integer.toString(contadorEstados));
                estadosEp.add(estado2);
                contadorEstados++;      
                estadosFinales.add(estado2);
                funcionesEp.add(new Funcion(estadoQ_0, raiz.darContenido(), estado2));
                Automata a = new Automata(estadoQ_0, estadosEp, estadosFinales, funcionesEp, leng, Automata.AFN);                                 
                return a;
            case "|":
                ArrayList<Estado> estadosOr = new ArrayList();                
                ArrayList<Estado> estadosFinalesOr = new ArrayList();
                ArrayList<Funcion> funcionesOr = new ArrayList();
                Estado orQ_0;
                if(izquierdaFinal!=null)
                    orQ_0 = izquierdaFinal;
                else
                    orQ_0 = new Estado("S"+contadorEstados); 
                if(orQ_0 != izquierdaFinal)
                    contadorEstados++;
                estadosOr.add(orQ_0);
                Automata orIzq = thompson(raiz.darHijoIzquierdo(), leng, null);
                Automata orDer = thompson(raiz.darHijoDerecho(), leng, null);                                
                estadosOr.addAll(orIzq.estados);
                estadosOr.addAll(orDer.estados);
                Estado fin = new Estado("S"+Integer.toString(contadorEstados));
                contadorEstados++;
                estadosFinalesOr.add(fin);
                estadosOr.add(fin);                                
                funcionesOr.add(new Funcion(orQ_0, "¬", orIzq.estadoInicial));
                funcionesOr.add(new Funcion(orQ_0, "¬", orDer.estadoInicial));
                funcionesOr.add(new Funcion(orIzq.estadosFinales.get(0), "¬", fin));
                funcionesOr.add(new Funcion(orDer.estadosFinales.get(0), "¬", fin));                
                funcionesOr.addAll(orIzq.funciones);
                funcionesOr.addAll(orDer.funciones);                          
                Automata or = new Automata(orQ_0, estadosOr, estadosFinalesOr, funcionesOr, leng, Automata.AFD);
                return or;
            case ".":
                ArrayList<Estado> estadosConcat = new ArrayList();                
                ArrayList<Estado> estadosFinalesConcat = new ArrayList();
                ArrayList<Funcion> funcionesConcat = new ArrayList();                
                Automata izq = thompson(raiz.darHijoIzquierdo(), leng, null);
                Automata der = thompson(raiz.darHijoDerecho(), leng, izq.estadosFinales.get(0));
                Estado estadoConcatQ_0 = izq.estadoInicial;
                der.estados.remove(der.estadoInicial);
                //der.estadoInicial = izq.estadosFinales.get(0);                
                estadosConcat.addAll(izq.estados);
                estadosConcat.addAll(der.estados);
                estadosFinalesConcat.add(der.estadosFinales.get(0));
                funcionesConcat.addAll(izq.funciones);
                funcionesConcat.addAll(der.funciones);                 
                Automata concat = new Automata(estadoConcatQ_0, estadosConcat, estadosFinalesConcat, funcionesConcat, leng, Automata.AFN);
                return concat;
            case "*":
                ArrayList<Estado> estadosKleene = new ArrayList();                
                ArrayList<Estado> estadosFinalesKleene = new ArrayList();
                ArrayList<Funcion> funcionesKleene = new ArrayList();
                Estado estadoKleeneQ_0;
                if(izquierdaFinal!=null)
                    estadoKleeneQ_0 = izquierdaFinal;
                else
                    estadoKleeneQ_0 = new Estado("S"+contadorEstados);                
                estadosKleene.add(estadoKleeneQ_0);
                if(estadoKleeneQ_0 != izquierdaFinal)
                    contadorEstados++;                                
                Automata c = thompson(raiz.darHijoIzquierdo(), leng, null);
                estadosKleene.addAll(c.estados);
                Estado estadoKleeneFinal = new Estado("S"+contadorEstados);
                estadosFinalesKleene.add(estadoKleeneFinal);
                estadosKleene.add(estadoKleeneFinal);
                contadorEstados++;                
                funcionesKleene.add(new Funcion(estadoKleeneQ_0, "¬", c.estadoInicial));
                funcionesKleene.add(new Funcion(estadoKleeneQ_0, "¬", estadoKleeneFinal));
                funcionesKleene.add(new Funcion(c.estadosFinales.get(0), "¬", c.estadoInicial));
                funcionesKleene.add(new Funcion(c.estadosFinales.get(0), "¬", estadoKleeneFinal));                
                funcionesKleene.addAll(c.funciones);                
                Automata kleene = new Automata(estadoKleeneQ_0, estadosKleene, estadosFinalesKleene, funcionesKleene, leng, Automata.AFN);
                return kleene;
            default:                
                ArrayList<Estado> estadosDef = new ArrayList();                
                ArrayList<Estado> estadosFinalesDef = new ArrayList();
                ArrayList<Funcion> funcionesDef = new ArrayList();
                Estado defQ_0;
                if(izquierdaFinal!=null)
                    defQ_0 = izquierdaFinal;
                else
                    defQ_0 = new Estado("S"+contadorEstados);
                estadosDef.add(defQ_0);
                if(defQ_0 != izquierdaFinal)
                    contadorEstados++;                
                Estado estadoFinalDef = new Estado("S"+contadorEstados);
                estadosFinalesDef.add(estadoFinalDef);
                estadosDef.add(estadoFinalDef);
                contadorEstados++;
                funcionesDef.add(new Funcion(defQ_0, raiz.darContenido(), estadoFinalDef));                
                Automata car = new Automata(defQ_0, estadosDef, estadosFinalesDef, funcionesDef, leng, Automata.AFN);
                return car;
        }                       
    }
    
    public boolean simulacionAFN(String w, Automata AFN)
    {        
        ArrayList<Estado> s_0 = new ArrayList();
        s_0.add(AFN.estadoInicial);
        ArrayList<Estado> s = AFN.cerraduraEpsilon(s_0);
        for(int i = 0; i < w.length(); i++)
        {
            s = AFN.cerraduraEpsilon(AFN.mover(s, w.charAt(i) + ""));                        
        }
        boolean centinela = false;
        for(int u = 0; u < s.size() && !centinela; u++)
        {
            for(int b = 0; b < AFN.estadosFinales.size() && !centinela; b++)
            {
                if(s.get(u).equals(AFN.estadosFinales.get(b)))                    
                    centinela = true;
            }
        }
        return centinela;
    }
    
    public ArrayList simulacionAFD(String w, Automata AFD)
    {
        ArrayList tokens = new ArrayList();        
        Estado eInicial = AFD.estadoInicial;
        ArrayList<Estado> res = new ArrayList();
        res.add(eInicial);
        ArrayList<Estado> s = AFD.cerraduraEpsilon(res);
        Estado ultimaAceptacion = null;
        int ultimoInt = 0;
        for(int i = 0; i < w.length(); i++)
        {
            s = AFD.cerraduraEpsilon(AFD.mover(s, w.charAt(i)+""));
            if(AFD.estadosFinales.contains(s.get(0)))
            {
                ultimaAceptacion = s.get(0);
                ultimoInt = i;
            }
        }
        boolean aceptado = false;
        for(int u=0; u<AFD.estadosFinales.size() && !aceptado; u++)
        {
            if(s.contains(AFD.estadosFinales.get(u)))
                aceptado = true; 
        }
        tokens.add(ultimoInt);
        tokens.add(ultimaAceptacion);
        return tokens; 
    }
    
    public boolean anulable(Node nodo)
    {
        switch (nodo.darContenido())
        {
            case "¬":
                return true;
            case "|":
                if(anulable(nodo.darHijoDerecho()) || anulable(nodo.darHijoIzquierdo()))
                    return true;
                else
                    return false;
            case ".":
                if(anulable(nodo.darHijoDerecho()) && anulable(nodo.darHijoIzquierdo()))
                    return true;
                else
                    return false;
            case "*":
                return true;
            default:
                return false;           
        }
    }
    
    public ArrayList<Integer> primeraPos(Node n) //TODO Review the pp part. It could be duplicates
    {
        switch (n.darContenido())
        {
            case "¬":
                ArrayList<Integer> vacio = new ArrayList();
                return vacio;
            case "|":                
                ArrayList<Integer> primeraPosIzq = primeraPos(n.darHijoIzquierdo());
                ArrayList<Integer> primeraPosDer = primeraPos(n.darHijoDerecho());
                ArrayList<Integer> arrayUnion = primeraPosDer;                
                for(int i = 0; i < primeraPosIzq.size(); i++)
                {
                    boolean existe = false;
                    for(int u = 0; u < arrayUnion.size() && !existe; u++)
                    {
                        if(primeraPosIzq.get(i).equals(arrayUnion.get(u)))
                            existe = true;                            
                    }
                    if(!existe)
                        arrayUnion.add(primeraPosIzq.get(i));
                    
                }
                return arrayUnion;
            case ".":
                ArrayList<Integer> primeraPIzq = primeraPos(n.darHijoIzquierdo());
                ArrayList<Integer> primeraPDer = primeraPos(n.darHijoDerecho());
                ArrayList<Integer> arrayU = primeraPDer; 
                if(anulable(n.darHijoIzquierdo()))
                {                                   
                    for(int i = 0; i < primeraPIzq.size(); i++)
                    {
                        boolean existe = false;
                        for(int u = 0; u < arrayU.size() && !existe; u++)
                        {
                            if(primeraPIzq.get(i).equals(arrayU.get(u)))
                                existe = true;                            
                        }
                        if(!existe)
                            arrayU.add(primeraPIzq.get(i));                        
                    }
                    return arrayU;
                }
                else
                    return primeraPIzq;
            case "*":
                return primeraPos(n.darHijoIzquierdo());
            default:                
                ArrayList<Integer> i = new ArrayList();                
                if(!pp.containsValue(n))
                {
                    i.add(pp.size());
                    pp.put(pp.size(),n);
                    return i;                
                }
                else
                {                    
                    for(Object o : pp.keySet())
                    {
                        if(pp.get(o).equals(n))
                        {                        
                            i.add((Integer) o);                           
                        }
                    }
                }
                return i;
        }
    }
    
    public ArrayList<Integer> ultimaPos(Node n)
    {
        switch(n.darContenido())
        {
            case "¬":
                ArrayList<Integer> vacio = new ArrayList();
                return vacio;
            case "|":
                ArrayList<Integer> ultimaPosIzq = ultimaPos(n.darHijoIzquierdo());
                ArrayList<Integer> ultimaPosDer = ultimaPos(n.darHijoDerecho());
                ArrayList<Integer> arrayUnion = ultimaPosDer;                
                for(int i = 0; i < ultimaPosIzq.size(); i++)
                {
                    boolean existe = false;
                    for(int u = 0; u < arrayUnion.size() && !existe; u++)
                    {
                        if(ultimaPosIzq.get(i).equals(arrayUnion.get(u)))
                            existe = true;                            
                    }
                    if(!existe)
                        arrayUnion.add(ultimaPosIzq.get(i));
                    
                }
                return arrayUnion;
            case ".":
                ArrayList<Integer> ultimaPIzq = ultimaPos(n.darHijoIzquierdo());
                ArrayList<Integer> ultimaPDer = ultimaPos(n.darHijoDerecho());
                ArrayList<Integer> arrayU = ultimaPDer; 
                if(anulable(n.darHijoDerecho()))
                {                                   
                    for(int i = 0; i < ultimaPIzq.size(); i++)
                    {
                        boolean existe = false;
                        for(int u = 0; u < arrayU.size() && !existe; u++)
                        {
                            if(ultimaPIzq.get(i).equals(arrayU.get(u)))
                                existe = true;                            
                        }
                        if(!existe)
                            arrayU.add(ultimaPIzq.get(i));                        
                    }
                    return arrayU;
                }
                else
                    return ultimaPDer;
            case "*":
                return (ultimaPos(n.darHijoIzquierdo()));
            default:
                ArrayList<Integer> i = new ArrayList();
                boolean found = false; 
                for(Object o : pp.keySet())
                {
                    if(pp.get(o).equals(n) && !found)
                    {                        
                        i.add((Integer) o);
                        found = true;
                    }
                }
                return i;
        }
    }
    
    public boolean siguientePos(Node n)
    {
        if(n!=null)
        {
            switch (n.darContenido())
            {
                case ".":
                    ArrayList<Integer> upIzq = ultimaPos(n.darHijoIzquierdo());
                    ArrayList<Integer> ppDer = primeraPos(n.darHijoDerecho());                    
                    for(int i = 0; i < upIzq.size(); i++)
                    {                        
                        if(sp.containsKey(upIzq.get(i)))
                        {
                            ArrayList<Integer> v = (ArrayList) sp.get(upIzq.get(i));
                            for(int rep = 0; rep < v.size() ; rep++)
                            {
                                if(!ppDer.contains(v.get(rep)))
                                    ppDer.add(v.get(rep));                                    
                            }              
                            sp.put(upIzq.get(i), ppDer);
                        }
                        else      
                        {
                            sp.put(upIzq.get(i), ppDer);                    
                        }
                    }
                    siguientePos(n.darHijoIzquierdo());
                    siguientePos(n.darHijoDerecho());
                    return true;
                case "*":
                    ArrayList<Integer> upN = ultimaPos(n);
                    ArrayList<Integer> ppN = primeraPos(n);
                    for(int u = 0; u < upN.size(); u++)
                    {
                        if(sp.containsKey(upN.get(u)))
                        {
                            ArrayList<Integer> p = (ArrayList) sp.get(upN.get(u));
                            for(int rept = 0; rept < p.size(); rept++)
                            {
                                if(!ppN.contains(p.get(rept)))
                                    ppN.add(p.get(rept));
                            }                            
                            sp.put(upN.get(u), ppN);
                        }
                        else
                        {
                            sp.put(upN.get(u), ppN);                    
                        }
                    }
                    siguientePos(n.darHijoIzquierdo());
                    return true;
                default:
                    siguientePos(n.darHijoIzquierdo());
                    siguientePos(n.darHijoDerecho());
                    return false;
            }
        }
        else
            return false;                  
    }
    
    public Automata construccionDirecta(Node n, ArrayList<String> leng) //TODO ALL
    {        
        ArrayList<Estado> Q = new ArrayList();
        ArrayList<Funcion> funcs = new ArrayList();
        ArrayList<Estado> eFinales = new ArrayList();
        Estado eInicial = new Estado("0");       
        HashMap equivalencias = new HashMap();
        ArrayList<Integer> ppInicial = primeraPos(n);
        equivalencias.put(eInicial, ppInicial);       
        siguientePos(n);       
        for(int i = 0; i < equivalencias.size(); i++)
        {
            //Parte en la que se localiza la siguiente Key a utilizar. 
            Iterator todos = equivalencias.keySet().iterator();   
            Estado estadoS = null;
            boolean salir = false;                        
            while(todos.hasNext() && !salir)
            {                
                Estado pivot = (Estado) todos.next();
                if(pivot.valor.equals(Integer.toString(i)))
                {
                    estadoS = pivot;
                    salir = true; 
                }
            }
            ArrayList<Integer> s = (ArrayList) equivalencias.get(estadoS);
            
            for(int u=0; u<leng.size();u++)
            {
                ArrayList<Integer> res = new ArrayList();
                for(int w = 0; w < s.size(); w++)
                {
                    Node nod = (Node) pp.get(s.get(w));
                    if(nod.darContenido().equals(leng.get(u)))
                        res.addAll((ArrayList) sp.get(s.get(w)));
                }
                if(!equivalencias.containsValue(res) && !res.isEmpty())                    
                {
                    Estado e = new Estado(Integer.toString(equivalencias.size()));
                    equivalencias.put(e, res);
                    funcs.add(new Funcion(estadoS, leng.get(u), e));
                }
                else
                {
                    Iterator en = equivalencias.keySet().iterator();
                    while(en.hasNext())
                    {
                        Estado es = (Estado) en.next();
                        if(compararArrays(((ArrayList) equivalencias.get(es)), res))
                            funcs.add(new Funcion(estadoS, leng.get(u), es));
                    }
                }
            }                      
        }
        Iterator lastLoop = equivalencias.keySet().iterator();
        while(lastLoop.hasNext())
        {            
            Estado est = (Estado) lastLoop.next();
            int fin = pp.size() - 1;                      
            ArrayList<Integer> aFinal = (ArrayList) equivalencias.get(est);
            if(aFinal.contains(fin))
                eFinales.add(est);
            Q.add(est);
            funcs.add(new Funcion(est, "¬", est));
        }
        return new Automata(eInicial, Q, eFinales, funcs, leng, Automata.AFD);
    }
    
    public boolean compararArrays(ArrayList a, ArrayList b)
    {        
        if(a.containsAll(b) && a.size()==b.size())
            return true;
        else
            return false;  
    }   
    
    public boolean validarCadena(String cadena)
    {
        Pattern reg = Pattern.compile(           
            "^                # Anchor to start of string\n" +
            "[0-9A-Za-z+*$()|\\#¬]+  # Match one or more valid characters\n" +
            "$                # Anchor to end of string\n",
            Pattern.COMMENTS);
        Matcher m = reg.matcher(cadena);
        if (m.find() && checkParens(cadena)) 
        {
            System.out.print("OK: String has only valid characters and balanced parenthesis.\n");
            return true;
        }
        else 
        {
            System.out.print("ERROR: String has invalid characters or unbalanced parenthesis.\n");
            return false;//System.exit(0);
        }
    }
    
    public static Boolean checkParens(String s) {
        Pattern regex = Pattern.compile("\\(([^()]*)\\)");
        Matcher m = regex.matcher(s);
        // Loop removes matching nested parentheses from inside out.
        while (m.find()) {
            s = m.replaceFirst(m.group(1));
            m.reset(s);
        }
        regex = Pattern.compile("[()]");
        m = regex.matcher(s);
        // Check if there are any erroneous parentheses left over.
        if (m.find()) {
            return false;   // String has unbalanced parens.
        }
        return true;        // String has balanced parens.
    }
    
    public boolean isInteger( String input )  
    {  
       try  
       {  
          Integer.parseInt( input );  
          return true;  
       }  
       catch( Exception e)  
       {  
          return false;  
       }  
    }        
}

class Loader
{
    
    //--------------------------------------------------------------------------
    // ATRIBUTOS
    //--------------------------------------------------------------------------
    public HashMap characters;
    public HashMap keywords;
    public HashMap tokens;
    public HashMap productions;
    public HashMap regCharacters;
    public HashMap regKeywords;
    public HashMap regTokens;
    public HashMap regProductions;
    
    //Reader related
    private CharBuffer input;
    private static final int LOOKAHEAD_DEPTH = 11;
    
    //--------------------------------------------------------------------------
    // CONSTRUCTOR
    //--------------------------------------------------------------------------
    public Loader(Reader f)
    {
        input = new CharBuffer(f, LOOKAHEAD_DEPTH);
        characters = new HashMap();
        keywords = new HashMap();
        tokens = new HashMap();
        productions = new HashMap();
        regCharacters = new HashMap();
        regKeywords = new HashMap();
        regTokens = new HashMap();
        regProductions = new HashMap();
        
    }
    
    //--------------------------------------------------------------------------
    // METODOS
    //--------------------------------------------------------------------------              
    private int LA(int i) { return input.LA(i); }
    private void consume() { input.consume(); }
    private void match(int c) { consume(); }
    
    public void inputFile() 
    {
        while ( LA(1) != -1 ) 
        {
            //Match de comentarios
            if ( LA(1)=='(' && LA(2)=='.') 
            { 
                comment();
            }
            
            // Match the word COMPILER
            else if ( LA(1) == 'C' && LA(2) == 'O' && LA(3) == 'M' && LA(4) == 'P' && LA(5) == 'I' && LA(6) == 'L' && LA(7) == 'E' && LA(8) == 'R') 
            {
                kwCompiler();
                match(' ');
                name();                
            }
            
            // Match CHARACTERS
            else if(LA(1) == 'C' && LA(2) == 'H' && LA(3) == 'A' && LA(4) == 'R' && LA(5) == 'A' && LA(6) == 'C' && LA(7) == 'T' && LA(8) == 'E' && LA(9) == 'R' && LA(10) == 'S')
            {
                kwCharacters();
                while(LA(1)=='\n')
                    match('\n');
                while(LA(1)!='\n')
                {
                    assignmentCh();
                }                
            }
            
            // Match KEYWORDS
            else if(LA(1) == 'K' && LA(2) == 'E' && LA(3) == 'Y' && LA(4) == 'W' && LA(5) == 'O' && LA(6) == 'R' && LA(7) == 'D' && LA(8) == 'S')
            {
                kwKeywords();
                while(LA(1)=='\n')
                    match('\n');
                while(LA(1)!='\n')
                {
                    assignmentKw();
                }                
            }
            
            // Match TOKENS
            else if(LA(1) == 'T' && LA(2) == 'O' && LA(3) == 'K' && LA(4) == 'E' && LA(5) == 'N' && LA(6) == 'S')
            {
                kwTokens();
                while(LA(1)=='\n')
                    match('\n');
                while(LA(1)!='\n')
                {
                    assignmentTk();
                }                                
            }
            
            // Match PRODUCTIONS
            else if(LA(1) == 'P' && LA(2) == 'R' && LA(3) == 'O' && LA(4) == 'D' && LA(5) == 'U' && LA(6) == 'C' && LA(7) == 'T' && LA(8) == 'I' && LA(9) == 'O' && LA(10) == 'N' && LA(11) == 'S')
            {
                kwProductions();                
                //TODO Productions assignments?
            }
            
            // Match END
            else if(LA(1) == 'E' && LA(2) == 'N' && LA(3) == 'D')
            {
                kwEnd();
                match(' ');
                name();
            }
            
            else 
            {
                //assignment();
                match('\n');
            }
        }
    }
    
    public void assignmentCh() 
    {        
        String identifier = identifier();
        if(LA(1)==' ')
            match(' ');
        match('=');
        if(LA(1)==' ')
            match(' ');
        String value = value();
        characters.put(identifier, value);   
        match('\n');
    }    
    
    public void assignmentKw() 
    {
        String id = identifier();
        if(LA(1)==' ')
            match(' '); 
        match('=');
        if(LA(1)==' ')
            match(' ');
        String val = value();
        keywords.put(id, val);
        match('\n');
    }  
    
    public void assignmentTk() 
    {
        String id = identifier();
        if(LA(1)==' ')
            match(' ');
        match('=');
        if(LA(1)==' ')
            match(' ');
        String val = valueAndExcept();
        tokens.put(id, val);
        match('\n');
    }    
    
    public String identifier() /* TODO ACCORDING TO THE PROJECT */
    {
        @SuppressWarnings("StringBufferMayBeStringBuilder")
        StringBuffer s = new StringBuffer();
        while ( Character.isLetter((char)LA(1)) || Character.isDigit((char) LA(1)))
        {
            s.append((char)LA(1));
            consume();
        }        
        return s.toString(); 
    }
    
    public String identifierWithPar() /* TODO ACCORDING TO THE PROJECT */
    {
        @SuppressWarnings("StringBufferMayBeStringBuilder")
        StringBuffer s = new StringBuffer();
        while ( Character.isLetter((char)LA(1)) || Character.isDigit((char) LA(1)) || LA(1)=='(' || LA(1)==')')
        {
            s.append((char)LA(1));
            consume();
        }        
        return s.toString(); 
    }
    
    public String value() 
    {
        @SuppressWarnings("StringBufferMayBeStringBuilder")
        StringBuffer s = new StringBuffer();
        ArrayList<String> identifierIncluded = new ArrayList();
        if(LA(1)=='"')
        {
            match('"');
            while ( Character.isLetter((char)LA(1)) || Character.isDigit((char) LA(1)) ) 
            {
                s.append((char)LA(1));
                consume();
            }
            match('"');
            
            if(LA(1)=='\n')
                match('\n');
            else
            {
                while(LA(1)=='+')
                {
                    match('+');
                    identifierIncluded.add(identifier());
                }                
            }
        }
        
        else
        {
            identifierIncluded.add(identifier());
            while(LA(1)=='+' && LA(2)!='"')
            {
                identifierIncluded.add(identifier());
            }
            match('+');           
            match('"');
            while ( Character.isLetter((char)LA(1)) || Character.isDigit((char) LA(1)) ) 
            {
                s.append((char)LA(1));
                consume();
            }
            match('"');                        
        }
        String cadenaIdentifiersIncluded = "";
        for(int i = 0; i < identifierIncluded.size(); i++)
        {
            cadenaIdentifiersIncluded += (String) characters.get(identifierIncluded.get(i));
        }
        String cadenaCompleta = s.toString() + cadenaIdentifiersIncluded;
        match('.');
        return cadenaCompleta;
    }
    
    public String valueAndExcept()
    {
        StringBuffer s = new StringBuffer();
        String pivote = "";
        while(LA(1)!='\n')
        {
            if(LA(1)=='"')
            {
                pivote+='"';
                match('"');
                pivote += identifierWithPar();
                pivote+='"';
                match('"');
            }
            else if(LA(1)=='{')
            {
                pivote+=(char) LA(1);
                match('{');
                pivote+=identifier();
                pivote+= (char) LA(1);
                match('}');                
            }
            else if (LA(1)==' ')
            {
                consume();
                if(LA(1)=='E' && LA(2)=='X' && LA(3)=='C' && LA(4) == 'E' && LA(5)=='P' && LA(6) == 'T')
                {
                    kwExcept();
                    match(' ');
                    pivote+=" -";
                    pivote+=identifier();
                    match('.');
                }
            }
            else if(Character.isLetter((char) LA(1)) || Character.isDigit((char) LA(1)))
            {
                pivote+=identifier();
            }
            else
                match('\n');
        }
        return pivote;
        
    }

    public String comment() 
    {
        match('(');
        match('.');        
        StringBuffer s = new StringBuffer();
        while ( LA(1)!='.' && LA(2)!=')' ) 
        {
            s.append((char)LA(1));
            consume();
        }
        match('.');
        match(')');
        return s.toString();
    }
    
    public String name()            
    {
        StringBuffer s = new StringBuffer();
        while(Character.isLetter((char) LA(1)) || Character.isDigit((char) LA(1)))
        {
            s.append((char)LA(1));
            consume();
        }
        
        return s.toString();
    }
    
    public void transformarRegex()
    {
        Iterator iterator = characters.keySet().iterator();
        String pivotKey = "";
        String pivotValue = "";
        String pivotValueReg;
        
        /** Iterator para convertir los CHARACTERS */
        while(iterator.hasNext())
        {
            pivotKey = (String) iterator.next();
            pivotValue = (String) characters.get(pivotKey);
            pivotValueReg = "(";
            StringBuffer s = new StringBuffer();
            for(int i = 0; i < pivotValue.length(); i++)
            {
                if(i==0)
                    s.append(pivotValue.charAt(i));
                else
                {
                    s.append('|');
                    s.append(pivotValue.charAt(i));
                }
            }
            pivotValueReg += s.toString() + ")";
            regCharacters.put(pivotKey, pivotValueReg);
        }
        
        /** Convertir los KEYWORDS */
        //Las keywords se quedan igual, son concatenaciones
        iterator = keywords.keySet().iterator();
        while(iterator.hasNext())
        {
            pivotKey = (String) iterator.next();
            pivotValue = (String) keywords.get(pivotKey);
            regKeywords.put(pivotKey,pivotValue);
        }
        
        /** Convertir los TOKENS */
        iterator = tokens.keySet().iterator();
        while(iterator.hasNext())
        {
            pivotKey = (String) iterator.next();
            pivotValue = (String) tokens.get(pivotKey);
            pivotValueReg = "";
            @SuppressWarnings("StringBufferMayBeStringBuilder")
            StringBuffer s = new StringBuffer();
            boolean exception = false;
            int i = 0;
            while(i<pivotValue.length() && !exception)
            {
                if(Character.isLetter(pivotValue.charAt(i)) || Character.isDigit(pivotValue.charAt(i)) || pivotValue.charAt(i)=='{')
                {
                    while(Character.isLetter(pivotValue.charAt(i)) || Character.isDigit(pivotValue.charAt(i)))
                    {
                        s.append(pivotValue.charAt(i));
                        i++;
                    }
                    pivotValueReg += (String) regCharacters.get(s.toString());
                    if(pivotValue.charAt(i)=='{')
                    {
                        i++;
                        StringBuffer s1 = new StringBuffer();
                        while(Character.isLetter(pivotValue.charAt(i)) || Character.isDigit(pivotValue.charAt(i)))
                        {
                            s1.append(pivotValue.charAt(i));
                            i++;
                        }                
                        pivotValueReg += (String) regCharacters.get(s1.toString());
                        pivotValueReg+='*';                        
                    } 
                }
                if(pivotValue.charAt(i)=='-')
                    exception = true;
                i++;
            }
            regTokens.put(pivotKey, pivotValueReg);
        }
        
    }
    
    public void reemplazarSimbolosEspeciales()
    {
        Iterator it = characters.keySet().iterator();
    }
            
    
    public String kwCompiler() 
    {
        match('c');
        match('o');
        match('m');
        match('p');
        match('i');
        match('l');
        match('e');
        match('r');
        return "compiler";
    }
    
    public String kwKeywords()
    {
        match('k');
        match('e');
        match('y');
        match('w');
        match('o');
        match('r');
        match('d');
        match('s');        
        return "keywords";
    }
    
    public String kwTokens()
    {
        match('t');
        match('o');
        match('k');
        match('e');
        match('n');
        match('s');        
        return "tokens";
    }
    
    public String kwProductions()
    {
        match('p');
        match('r');
        match('o');
        match('d');
        match('u');
        match('c');
        match('t');
        match('i');
        match('o');
        match('n');
        match('s');           
        return "productions";
    }
    
    public String kwExcept()
    {
        match('e');
        match('x');
        match('c');
        match('e');
        match('p');
        match('t');        
        return "except";
    }
    
    public String kwCharacters()
    {
        match('c');
        match('h');
        match('a');
        match('r');
        match('a');
        match('c');
        match('t');
        match('e');
        match('r');
        match('s');        
        return "characters";
    }
    
    public String kwEnd()
    {
        match('e');
        match('n');
        match('d');
        return "end";
    }   
}

class CharBuffer 
{
    //--------------------------------------------------------------------------
    // ATRIBUTOS
    //--------------------------------------------------------------------------    
    private int[] buf;
    private Reader f;
    private int k;
    
    //--------------------------------------------------------------------------
    // CONSTRUCTOR
    //--------------------------------------------------------------------------    
    public CharBuffer(Reader in, int m)
    {
        k = m; 
        buf = new int[k];
        f = in;
        try
        {
            for(int i = 0; i<k; i++)
            {
                buf[i] = f.read();
            }
        }
        catch (IOException io)
        {
            System.err.println(io.getMessage());
            System.exit(1);
        }
    }
    
    //--------------------------------------------------------------------------
    // METODOS
    //--------------------------------------------------------------------------    
    public int LA(int i)
    {
        if( i>=i && i<=k)
            return buf[i-1];
        return 0;
    }
    
    public void consume() 
    {        
        for (int i=0; i<k-1; i++) 
        {
            buf[i]=buf[i+1];
        }        
        try 
        {
            buf[k-1] = f.read();
            if ( buf[k-1]=='\r' )             
                buf[k-1] = f.read();       
        }
        catch (IOException io) 
        {
            System.err.println(io.getMessage());
            System.exit(1);
        }
    }            
}

public class Compilador {
    
    //--------------------------------------------------------------------------
    // ATRIBUTOS
    //--------------------------------------------------------------------------
    private static Scanner scanner;
    private static Loader loader;
    private static HashMap automatas;
    private static Automata autGeneral;
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) 
    {
        //procesarAutomatas
        automatas = new HashMap();
        try
        {
            loadInputFile("Ejemplo.txt");
        }
        catch(IOException e)
        {
            e.getMessage();
            System.exit(1);
        }
        	 construirAutomata("(A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)(A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)(0|1|2|3|4|5|6|7|8|9)*");
	 construirAutomata("(0|1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)*");

        automataGeneral();
        autGeneral = autGeneral.toAFD();
		
		
		Scanner scanner = new Scanner("IN.txt");
        String archivoCompleto = "";
        while(scanner.hasNext())
        {
            archivoCompleto += scanner.next();
        }
        while(archivoCompleto != "")
        {
            try
            {
                escribirTokens(archivoCompleto);              
            }
            catch(Exception e){}
            
        }
        System.exit(0);       
    }
	
	public static void escribirTokens(String cadena) throws IOException
    {     
        FileWriter fWrite = new FileWriter("Tokens.txt");
        BufferedWriter writer = new BufferedWriter(fWrite);  
        Parser parser = new Parser();
        ArrayList tokens = parser.simulacionAFD(cadena, autGeneral);        
        int pos = (int) tokens.get(0);        
        Funcion func = (Funcion) tokens.get(2);
        writer.write(cadena.substring(0, (int) tokens.get(0)));
    }
    
    public static void automataGeneral()
    {
        Estado eInicialGeneral = new Estado("S0");
        Estado eFinalGeneral = new Estado("SN");
        Iterator it = automatas.keySet().iterator();
        autGeneral = new Automata(eInicialGeneral);
        autGeneral.anhadirEstadoFinal(eFinalGeneral);
        String pivotKey;        
        Automata pivotAut;
        Funcion pivotFun;
        while(it.hasNext())
        {
            pivotKey = (String) it.next();
            pivotAut = (Automata) automatas.get(pivotKey);
            pivotFun = new Funcion(eInicialGeneral, "¬", pivotAut.estadoInicial);            
            autGeneral.anhadirFuncion(pivotFun);
            for(int i = 0; i < pivotAut.estadosFinales.size(); i++)
            {
                pivotFun = new Funcion(pivotAut.estadosFinales.get(i), "¬", eFinalGeneral);
                autGeneral.anhadirFuncion(pivotFun);
            }
            autGeneral.estados.add(eInicialGeneral);
            autGeneral.estados.addAll(pivotAut.estados);
            autGeneral.funciones.addAll(pivotAut.funciones);
            autGeneral.anhadirAlLenguaje(pivotAut.lenguaje);
        }        
    }
    
    public static void loadInputFile(String path) throws IOException
    {
        /*Read input file*/
        BufferedReader f = new BufferedReader(new FileReader(path));
        loader = new Loader(f);
        loader.inputFile();
        f.close();
        loader.transformarRegex();
        //System.out.println(loader.darCadena());
        //System.exit(0);
    }
    
    public static void construirAutomata(String regex)
    {                
        Automata automata;
        ArrayList<String> leng;
        Parser parser;
        ArrayList array;
        Node arbol;           
        parser = new Parser();
        array = parser.convertirAPosfix(regex+'#');
        arbol = parser.crearArbol();
        leng = obtenerLenguaje(regex+'#');
        automata = parser.construccionDirecta(arbol, leng);
        automatas.put(regex+'#', automata);        
    }
    
    
    public static String sustituirOperaciones(String cadena)
    {                
        if(cadena.contains("+"))
        {            
            for(int i = 0; i < cadena.length(); i++)
            {
                if(cadena.charAt(i)=='+')
                {
                    String unoAntes = cadena.charAt(i-1)+"";
                    String cadenaRep = unoAntes +"*";                    
                    cadena = cadena.replaceFirst("\\+", cadenaRep);
                }
            }
        }               
        if(cadena.contains("?"))
        {
            cadena = cadena.replaceAll("\\?","|¬");
        }
        return cadena;
    }
    
    public static ArrayList<String> obtenerLenguaje(String cadena)
    {
        ArrayList<String> lenguaje = new ArrayList();
        for(int i = 0; i < cadena.length(); i++)
        {
            boolean centinela = false; 
            for(int u = 0; u < lenguaje.size() && !centinela; u++)
            {
                if(lenguaje.get(u).equals(cadena.charAt(i)+""))
                    centinela = true;
            }
            
            if(!centinela && (Character.isAlphabetic(cadena.charAt(i)) || cadena.charAt(i) == '¬'))
                lenguaje.add(cadena.charAt(i)+"");
        }
        
        return lenguaje;
    }
}